﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Bzure.Common.Core;
using Bzure.Common.Transactions;

namespace Bzure.Common.Data
{
    public abstract class Repository
    {
        #region Static
        protected static Dictionary<Type, Dictionary<string, MemberDataMap>> DataMapContainer = new Dictionary<Type, Dictionary<string, MemberDataMap>>();
        protected static Dictionary<Type, Delegate> QueryMapContainer = new Dictionary<Type, Delegate>();
        public static void AppendDataMap<T>(Type EntityType, string DataFieldName, Expression<Func<T>> e)
        {
            MemberDataMap MemberDataMap = new MemberDataMap()
            {
                MemberName = MemberHelper.GetName(e),
                DataFieldName = DataFieldName
            };
            Dictionary<string, MemberDataMap> mapSub;
            if (!DataMapContainer.TryGetValue(EntityType, out mapSub))
            {
                mapSub = new Dictionary<string, MemberDataMap>();
                DataMapContainer[EntityType] = mapSub;
            }
            mapSub[MemberDataMap.MemberName] = MemberDataMap;
        }
        #endregion

        protected ITransactionSupport ContractProvider;
        public Repository(ITransactionSupport contractProvider)
        {
            this.ContractProvider = contractProvider;
        }
        /// <summary>
        /// 实体对应的表名
        /// </summary>
        public abstract string TableName { get; }
        #region 实体更新
        string UpdateSqlTemplate = "UPDATE {0} SET {1} WHERE {2}";
        string InsertSqlTemplate = "INSERT INTO {0}{1}";
        string DeleteSqlTemplate = "DELETE FROM {0} WHERE {1}";

        /// <summary>
        /// 实体操作
        /// </summary>
        /// <param name="EntityMap"></param>
        public void ProcessEntityPostRequest<Entity>(Bzure.Common.Data.EntityPostRequest EntityMap) where Entity : IEntity, IPersistenceState
        {
            Dictionary<string, MemberDataMap> MapSet = new Dictionary<string, MemberDataMap>();
            lock (DataMapContainer)
            {
                Dictionary<string, MemberDataMap> MapSetTemp;
                if (DataMapContainer.TryGetValue(typeof(Entity), out MapSetTemp))
                {
                    foreach (KeyValuePair<string, MemberDataMap> kvp in MapSetTemp)
                    {
                        MapSet[kvp.Key] = kvp.Value.Copy();
                    }
                }
                else
                {
                    throw new Exception(string.Format("类型：{0}没有在构建静态构造中初始化实体{1}的数据映射", this.GetType().Name, typeof(Entity).Name));
                }
            }
            switch (EntityMap.Method)
            {
                #region Update
                case Bzure.Common.Data.EntityPostRequest.EntityPostMethod.Update:
                    //要更新的字段
                    List<IDataMemberMap> FieldDataMemberMapList = new List<IDataMemberMap>();
                    foreach (EntityMemberMap map in EntityMap.FieldMap)
                    {
                        MemberDataMap MemberDataMap;
                        if (MapSet.TryGetValue(map.MemberName, out MemberDataMap))
                        {
                            FieldDataMemberMapList.AppendMember(MemberDataMap, map);
                        }

                    }
                    //更新的条件
                    List<IDataMemberMap> ConditionDataMemberMapList = new List<IDataMemberMap>();
                    foreach (IEntityMemberMap map in EntityMap.ConditionMap)
                    {
                        if (map is EntityMemberMap)
                        {
                            EntityMemberMap EntityMemberMap = map as EntityMemberMap;
                            MemberDataMap MemberDataMap;
                            if (MapSet.TryGetValue(EntityMemberMap.MemberName, out MemberDataMap))
                            {
                                ConditionDataMemberMapList.AppendMember(MemberDataMap, EntityMemberMap);
                            }
                        }
                        else if (map is LogicLinkMap)
                        {
                            ConditionDataMemberMapList.Add(map as LogicLinkMap);
                        }

                    }
                    StringBuilder updateSql = new StringBuilder();
                    updateSql.AppendFormat(UpdateSqlTemplate, this.TableName, BuildUpdateSqlSub(FieldDataMemberMapList), BuildConditonSqlSub(ConditionDataMemberMapList));
                    EntityMap<Entity> updateHandler = this.CreateEntityMap<Entity>(updateSql.ToString());
                    //添加字段参数
                    foreach (DataMemberMap DataMemberMap in FieldDataMemberMapList.Where(m => (m is DataMemberMap)))
                    {
                        updateHandler.AddParameter(DataMemberMap);
                    }
                    //添加条件参数
                    foreach (DataMemberMap DataMemberMap in ConditionDataMemberMapList.Where(m => (m is DataMemberMap)))
                    {
                        updateHandler.AddParameter(DataMemberMap);
                    }
                    updateHandler.AsNonQuery();
                    if (EntityMap.Entity is IPersistenceState)
                    {
                        IPersistenceState persistenceObject = EntityMap.Entity as IPersistenceState;
                        persistenceObject.MarkPersistenceState(true);
                    }
                    if (EntityMap.Entity is ILastUpdate)
                    {
                        ILastUpdate lastUpdateObject = EntityMap.Entity as ILastUpdate;
                        lastUpdateObject.LastTime = DateTime.Now;
                    }
                    break;
                #endregion
                #region Delete
                case Bzure.Common.Data.EntityPostRequest.EntityPostMethod.Delete:
                    //删除的条件
                    List<IDataMemberMap> ConditionDataMemberMapListForDelete = new List<IDataMemberMap>();
                    foreach (IEntityMemberMap map in EntityMap.ConditionMap)
                    {
                        if (map is EntityMemberMap)
                        {
                            EntityMemberMap EntityMemberMap = map as EntityMemberMap;
                            MemberDataMap MemberDataMap;
                            if (MapSet.TryGetValue(EntityMemberMap.MemberName, out MemberDataMap))
                            {
                                ConditionDataMemberMapListForDelete.AppendMember(MemberDataMap, EntityMemberMap);
                            }
                        }
                        else if (map is LogicLinkMap)
                        {
                            ConditionDataMemberMapListForDelete.Add(map as LogicLinkMap);
                        }

                    }
                    StringBuilder deleteSql = new StringBuilder();
                    deleteSql.AppendFormat(DeleteSqlTemplate, this.TableName, BuildConditonSqlSub(ConditionDataMemberMapListForDelete));
                    EntityMap<Entity> deleteHandler = this.CreateEntityMap<Entity>(deleteSql.ToString());

                    //添加条件参数
                    foreach (DataMemberMap DataMemberMap in ConditionDataMemberMapListForDelete.Where(m => (m is DataMemberMap)))
                    {
                        deleteHandler.AddParameter(DataMemberMap);
                    }
                    deleteHandler.AsNonQuery();
                    if (EntityMap.Entity is IPersistenceState)
                    {
                        IPersistenceState persistenceObject = EntityMap.Entity as IPersistenceState;
                        persistenceObject.MarkPersistenceState(false);
                    }
                    break;
                #endregion
                #region Create
                case Bzure.Common.Data.EntityPostRequest.EntityPostMethod.Create:

                    //添加的字段
                    List<IDataMemberMap> FieldDataMemberMapListForInsert = new List<IDataMemberMap>();
                    foreach (EntityMemberMap map in EntityMap.FieldMap)
                    {
                        MemberDataMap MemberDataMap;
                        if (MapSet.TryGetValue(map.MemberName, out MemberDataMap))
                        {
                            FieldDataMemberMapListForInsert.AppendMember(MemberDataMap, map);
                        }

                    }
                    StringBuilder insertSql = new StringBuilder();
                    insertSql.AppendFormat(InsertSqlTemplate, this.TableName, BuildInsertSqlSub(FieldDataMemberMapListForInsert));
                    EntityMap<Entity> insertHandler = this.CreateEntityMap<Entity>(insertSql.ToString());

                    //添加字段参数
                    foreach (DataMemberMap DataMemberMap in FieldDataMemberMapListForInsert.Where(m => (m is DataMemberMap)))
                    {
                        insertHandler.AddParameter(DataMemberMap);
                    }
                    insertHandler.AsNonQuery();
                    if (EntityMap.Entity is IPersistenceState)
                    {
                        IPersistenceState persistenceObject = EntityMap.Entity as IPersistenceState;
                        persistenceObject.MarkPersistenceState(true);
                    }
                    if (EntityMap.Entity is ILastUpdate)
                    {
                        ILastUpdate lastUpdateObject = EntityMap.Entity as ILastUpdate;
                        lastUpdateObject.LastTime = DateTime.Now;
                    }
                    if (EntityMap.Entity is ICreateTime)
                    {
                        ICreateTime createTimeObject = EntityMap.Entity as ICreateTime;
                        createTimeObject.CreateTime = DateTime.Now;
                    }
                    break;
                #endregion

            }
        }
        string BuildConditonSqlSub(List<IDataMemberMap> DataMemberMaps)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(" 1=1 ");
            foreach (IDataMemberMap map in DataMemberMaps)
            {
                sb.Append(ParseWhereByParam(map));
            }
            return sb.ToString();
        }
        string BuildUpdateSqlSub(List<IDataMemberMap> DataMemberMaps)
        {
            StringBuilder sb = new StringBuilder();
            bool find = false;
            foreach (DataMemberMap map in DataMemberMaps)
            {
                if (find)
                    sb.Append(",");
                sb.Append(string.Format("{0}=@{1}", map.DataFieldName, map.ParameterName));
                find = true;
            }
            return sb.ToString();
        }
        string BuildInsertSqlSub(List<IDataMemberMap> DataMemberMaps)
        {
            StringBuilder sbField = new StringBuilder();
            StringBuilder sbValue = new StringBuilder();
            bool find = false;
            foreach (DataMemberMap map in DataMemberMaps.Where(m => (m is DataMemberMap)))
            {
                if (find)
                {
                    sbField.Append(",");
                    sbValue.Append(",");
                }
                sbField.Append(map.DataFieldName);
                sbValue.Append(string.Format("@{0}", map.ParameterName));
                find = true;
            }
            return string.Format("({0}) VALUES({1})", sbField.ToString(), sbValue.ToString());
        }
        #endregion
        #region 实体查询
        protected Entity[] ProcessEntityQueryRequestNonePaged<Entity>(EntityQueryRequest<Entity> QueryRequest) where Entity : IEntity
        {
            Dictionary<string, MemberDataMap> MapSet = new Dictionary<string, MemberDataMap>();
            lock (DataMapContainer)
            {
                Dictionary<string, MemberDataMap> MapSetTemp;
                if (DataMapContainer.TryGetValue(typeof(Entity), out MapSetTemp))
                {
                    foreach (KeyValuePair<string, MemberDataMap> kvp in MapSetTemp)
                    {
                        MapSet[kvp.Key] = kvp.Value.Copy();
                    }
                }
                else
                {
                    throw new Exception(string.Format("类型：{0}没有在构建静态构造中初始化实体{1}的数据更新映射", this.GetType().Name, typeof(Entity).Name));
                }
            }
            Delegate queryMap = null;
            if (!QueryMapContainer.TryGetValue(typeof(Entity), out queryMap))
            {
                throw new Exception(string.Format("类型：{0}没有在构建静态构造中初始化实体{1}的数据查询映射", this.GetType().Name, typeof(Entity).Name));
            }
            ResultMapDelegate<Entity> qMap = queryMap as ResultMapDelegate<Entity>;
            //查寻的条件
            List<IDataMemberMap> ConditionDataMemberMapList = new List<IDataMemberMap>();
            foreach (IEntityMemberMap map in QueryRequest.ConditionMap)
            {
                if (map is EntityMemberMap)
                {
                    EntityMemberMap EntityMemberMap = map as EntityMemberMap;
                    MemberDataMap MemberDataMap;
                    if (MapSet.TryGetValue(EntityMemberMap.MemberName, out MemberDataMap))
                    {
                        ConditionDataMemberMapList.AppendMember(MemberDataMap, EntityMemberMap);
                    }
                }
                else if (map is LogicLinkMap)
                {
                    ConditionDataMemberMapList.Add(map as LogicLinkMap);
                }
            }
            EntityMap<Entity> QueryHandler = this.CreateEntityMap<Entity>(BuildQuerySql(this.TableName, ConditionDataMemberMapList));
            //添加条件参数
            foreach (DataMemberMap DataMemberMap in ConditionDataMemberMapList.Where(m => (m is DataMemberMap)))
            {
                QueryHandler.AddParameter(DataMemberMap);
            }
            return QueryHandler.SetMap(qMap).AsList().ToArray();
        }
        protected abstract Entity[] ProcessEntityQueryRequestPaged<Entity>(Bzure.Common.Data.EntityPageQueryRequest<Entity> QueryRequest) where Entity : IEntity, IPersistenceState;

        public Entity[] ProcessEntityQueryRequest<Entity>(Bzure.Common.Data.EntityQueryRequest<Entity> QueryRequest) where Entity : Bzure.Common.Core.IEntity, IPersistenceState
        {
            List<Entity> entities = new List<Entity>();
            if (QueryRequest is EntityPageQueryRequest<Entity>)
            {
                entities.AddRange(ProcessEntityQueryRequestPaged<Entity>(QueryRequest as EntityPageQueryRequest<Entity>));
            }
            else
            {
                entities.AddRange(ProcessEntityQueryRequestNonePaged<Entity>(QueryRequest));
            }
            entities.ForEach(m => { m.MarkPersistenceState(true); });
            return entities.ToArray();
        }
        string BuildQuerySql(string TableName, List<IDataMemberMap> DataMemberMaps)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("SELECT * FROM {0} WHERE 1=1 ", TableName);
            foreach (IDataMemberMap map in DataMemberMaps)
            {
                sb.Append(ParseWhereByParam(map));
            }
            return sb.ToString();
        }
        #endregion
        protected string ParseWhereByValue(IDataMemberMap tmap)
        {
            if (tmap is DataMemberMap)
            {
                DataMemberMap map = tmap as DataMemberMap;
                string logicSymbol = "";
                switch (map.LogicSymbol)
                {
                    case EntityRequest.LogicSymbol.And:
                        logicSymbol = " AND ";
                        break;
                    case EntityRequest.LogicSymbol.Or:
                        logicSymbol = " OR ";
                        break;
                }
                switch (map.Operator)
                {
                    case EntityRequest.Operator.Than:
                        return string.Format(" {2} {0}>'{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.Lessthan:
                        return string.Format(" {2} {0}<'{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.LessthanAndEqual:
                        return string.Format(" {2} {0}<='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.ThanAndEqual:
                        return string.Format(" {2} {0}>='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.StartWith:
                        return string.Format(" {2} PATINDEX('{1}%',{0})>0 ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.EndWith:
                        return string.Format(" {2} PATINDEX('%{1}',{0})>0 ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.Contain:
                        return string.Format(" {2} PATINDEX('%{1}%',{0})>0 ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.NotEqual :
                        return string.Format(" {2} NOT {0}='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case  EntityRequest.Operator.BitFlagContain :
                        return string.Format(" {2} {0}&'{1}'='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    case EntityRequest.Operator.BitFlagNotContain:
                        return string.Format(" {2} {0}&'{1}'!='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                    default:
                        return string.Format(" {2} {0}='{1}' ", map.DataFieldName, map.DataValue, logicSymbol);
                }
            }
            else if (tmap is LogicLinkMap)
            {
                LogicLinkMap lmap = tmap as LogicLinkMap;
                string logicSymbol = "";
                switch (lmap.LogicSymbol)
                {
                    case EntityRequest.LogicSymbol.And:
                        logicSymbol = " AND ";
                        break;
                    case EntityRequest.LogicSymbol.Or:
                        logicSymbol = " OR ";
                        break;
                }
                switch (lmap.LogicLink)
                {
                    case EntityRequest.LogicLink.LeftBracket:
                        return logicSymbol + " ( 1=1";
                    case EntityRequest.LogicLink.RightBracket:
                        return ")";
                }
            }
            return "";
        }
        protected string ParseWhereByParam(IDataMemberMap tmap)
        {
            if (tmap is DataMemberMap)
            {
                DataMemberMap map = tmap as DataMemberMap;
                string logicSymbol = "";
                switch (map.LogicSymbol)
                {
                    case EntityRequest.LogicSymbol.And:
                        logicSymbol = " AND ";
                        break;
                    case EntityRequest.LogicSymbol.Or:
                        logicSymbol = " OR ";
                        break;
                }
                switch (map.Operator)
                {
                    case EntityRequest.Operator.Than:
                        return string.Format(" {1} {0}>@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.Lessthan:
                        return string.Format(" {1} {0}<@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.LessthanAndEqual:
                        return string.Format(" {1} {0}<=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.ThanAndEqual:
                        return string.Format(" {1} {0}>=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.StartWith:
                        return string.Format(" {1} PATINDEX(@{2}+'%',{0})>0 ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.EndWith:
                        return string.Format(" {1} PATINDEX('%'+@{2},{0})>0 ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.Contain:
                        return string.Format(" {1} PATINDEX('%'+@{2}+'%',{0})>0 ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.NotEqual:
                        return string.Format(" {1} NOT {0}=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case  EntityRequest.Operator.BitFlagContain :
                        return string.Format(" {1} {0}&@{2}=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    case EntityRequest.Operator.BitFlagNotContain:
                        return string.Format(" {1} {0}&@{2}!=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                    default:
                        return string.Format(" {1} {0}=@{2} ", map.DataFieldName, logicSymbol, map.ParameterName);
                }
            }
            else if (tmap is LogicLinkMap)
            {
                LogicLinkMap lmap = tmap as LogicLinkMap;
                string logicSymbol = "";
                switch (lmap.LogicSymbol)
                {
                    case EntityRequest.LogicSymbol.And:
                        logicSymbol = " AND ";
                        break;
                    case EntityRequest.LogicSymbol.Or:
                        logicSymbol = " OR ";
                        break;
                }
                switch (lmap.LogicLink)
                {
                    case EntityRequest.LogicLink.LeftBracket:
                        return logicSymbol + " ( 1=1";
                    case EntityRequest.LogicLink.RightBracket:
                        return ")";
                }
            }
            return "";
        }
        public static bool IsNull(object obj)
        {
            if (obj == null || obj == DBNull.Value || string.IsNullOrEmpty(obj.ToString().Trim()))
                return true;
            else
                return false;
        }
        protected void MarkPersistenceState(Bzure.Common.Core.IPersistenceState entity, bool IsPersisted)
        {
            entity.MarkPersistenceState(IsPersisted);
        }
        protected virtual EntityMap<T> CreateEntityMap<T>(string commandText)
        {
            return new SqlEntityMap<T>(this.ContractProvider, commandText);
        }
    }
}
